﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using LayeredArchitectureSample.DataTransferObjects;
using LayeredArchitectureSample.DomainModel;
using LayeredArchitectureSample.Infrastructure.Services;
using LayeredArchitectureSample.RandomDataProviders;
using LayeredArchitectureSample.ServiceContracts;

namespace LayeredArchitectureSample.ViewModel
{
    internal class MainViewModel
    {
        private readonly IApplicationController _applicationController;

        private readonly IServiceOperationInvoker<IRemoteWareRepository> _remoteWareRepository;
        private readonly IServiceOperationInvoker<IRemoteLocationRepository> _remoteLocationRepository;
        private readonly IServiceOperationInvoker<IRemoteRouteRepository> _remoteRouteRepository;
        private readonly IServiceOperationInvoker<ITripManager> _tripManager;
        private readonly IRandomRouteProvider _randomRouteProvider;
        private readonly IRandomWareProvider _randomWareProvider;
        private readonly IRandomLocationProvider _randomLocationProvider;
        private readonly IExceptionAwareServiceCodeRunner _codeRunner;

        public MainViewModel(
            IApplicationController applicationController, 
            IServiceOperationInvoker<IRemoteWareRepository> remoteWareRepository,
            IServiceOperationInvoker<IRemoteLocationRepository> remoteLocationRepository,
            IServiceOperationInvoker<IRemoteRouteRepository> remoteRouteRepository,
            IServiceOperationInvoker<ITripManager> tripManager,
            IRandomRouteProvider randomRouteProvider,
            IRandomWareProvider randomWareProvider,
            IRandomLocationProvider randomLocationProvider,
            IExceptionAwareServiceCodeRunner codeRunner)
        {
            if (applicationController == null) throw new ArgumentNullException("applicationController");
            if (remoteWareRepository == null) throw new ArgumentNullException("remoteWareRepository");
            if (remoteLocationRepository == null) throw new ArgumentNullException("remoteLocationRepository");
            if (remoteRouteRepository == null) throw new ArgumentNullException("remoteRouteRepository");
            if (tripManager == null) throw new ArgumentNullException("tripManager");
            if (randomRouteProvider == null) throw new ArgumentNullException("randomRouteProvider");
            if (randomLocationProvider == null) throw new ArgumentNullException("randomLocationProvider");
            if (codeRunner == null) throw new ArgumentNullException("codeRunner");

            _applicationController = applicationController;
            _codeRunner = codeRunner;
            _randomLocationProvider = randomLocationProvider;
            _randomWareProvider = randomWareProvider;
            _randomRouteProvider = randomRouteProvider;
            _tripManager = tripManager;
            _remoteWareRepository = remoteWareRepository;
            _remoteLocationRepository = remoteLocationRepository;
            _remoteRouteRepository = remoteRouteRepository;
        }

        public void CloseDown()
        {
            Application.Current.Shutdown();
        }

        public void BrowseWares()
        {
            _codeRunner.RunCode(
                ()=>
                {
                    IEnumerable<WareDto> wares =
                        _remoteWareRepository.Invoke(x => x.GetAll());

                    var waresViewModel = new WaresViewModel(wares.Select(w => new WareViewModel(w.Id, w.Code)), _remoteWareRepository, _applicationController, _codeRunner);

                    _applicationController.ShowWares(waresViewModel); 
                });
        }

        public void BrowseLocations()
        {
            _codeRunner.RunCode(
                () =>
                {
                    IEnumerable<LocationDto> locations =
                        _remoteLocationRepository.Invoke(repository => repository.GetAll());

                    var viewModel =
                        new LocationsViewModel(locations.Select(l => new LocationViewModel(l.Id, l.Name)), _remoteLocationRepository, _applicationController, _codeRunner);

                    _applicationController.ShowLocations(viewModel);
                });
        }

        public void BrowseRoutes()
        {
            _codeRunner.RunCode(
                () =>
                {
                    IEnumerable<RouteDto> routes =
                        _remoteRouteRepository.Invoke(repository => repository.GetAll());

                    var viewModel = new RoutesViewModel(
                        routes
                        .Select(r => new RouteViewModel(r.Waypoints.Select(wp=>new LocationViewModel(wp.Id, wp.Name)), r.Id)),
                        _remoteRouteRepository,
                        _randomLocationProvider,
                        _codeRunner);

                    _applicationController.ShowRoutes(viewModel);
                });
        }

        public void BrowseTrips()
        {
            _codeRunner.RunCode(
                () =>
                    {
                        IEnumerable<TripDto> trips =
                            _tripManager.Invoke(repository => repository.GetAll());

                        var viewModels = new List<TripViewModel>();

                        foreach (TripDto trip in trips)
                        {
                            var route = new RouteViewModel(
                                trip.Route.Waypoints.Select(wp => new LocationViewModel(wp.Id, wp.Name)),
                                                                  trip.Route.Id);

                            var wareInTripViewModels =
                                trip.Wares.Select(
                                    w => new WareInTripViewModel(new WareViewModel(w.Ware.Id, w.Ware.Code), w.Quantity));

                            viewModels.Add(new TripViewModel(wareInTripViewModels, trip.Id, route, trip.Status, (TripState)Enum.Parse(typeof(TripState), trip.State)));
                        }

                        var viewModel = new TripsViewModel(
                            viewModels,
                            _tripManager,
                            _randomRouteProvider,
                            _randomWareProvider,
                            _codeRunner);

                        _applicationController.ShowTrips(viewModel);
                    });
        }
    }
}